/*==============================================================================
             Copyright (c) 2009 - All rights reserved
================================================================================
File description:

    OpenGL function implement

================================================================================
      Date            Name                    Description of Change
19-Aug-2009  Jorbin.Gao                    Written
25-Aug-2009  Xiaofeng.Gu                   Written
$HISTORY$
==============================================================================*/

#include "StdAfx.h"
#include "OpenGLPlotter.h"
#include "math.h"

COpenGLPlotter::COpenGLPlotter(void)
{
}

COpenGLPlotter::~COpenGLPlotter(void)
{
}

void COpenGLPlotter::Plot(PlotType ePlotType, Streams& streams)
{
	switch (ePlotType)
	{
	case eLines:
		DrawLines(streams);
		break;

	case eLineArrow:
		DrawLineArrow(streams);
		break;
	}
}

void COpenGLPlotter::Draw2dLine(double x1, double y1, double x2, double y2)
{
	glBegin(GL_LINES);
		glVertex2d(x1, y1);
		glVertex2d(x2, y2);
	glEnd();
}

void COpenGLPlotter::SetLineWidth(int factor)
{
	GLfloat fLineWidth[2];
	glGetFloatv(GL_LINE_WIDTH_RANGE,fLineWidth);
	glLineWidth(factor*fLineWidth[0]);
}

void COpenGLPlotter::DrawCylinder(double dia, double height)
{
	double nx,ny;
	int ii;
	double radius = dia/2;
	
	glBegin(GL_QUAD_STRIP);
		for(ii=0; ii<=360; ii++)
		{
			nx=cos(ii*SK_PI/180);
			ny=sin(ii*SK_PI/180);
			glNormal3d(nx,ny,0);
			glVertex3d(radius*cos(ii*SK_PI/180), 0.0, radius*sin(ii*SK_PI/180));
			glVertex3d(radius*cos(ii*SK_PI/180), height, radius*sin(ii*SK_PI/180));
		}
	glEnd();

}

void COpenGLPlotter::DrawBox3D(double xMin, double xMax, 
							double yMin, double yMax,
							double zMin, double zMax)
{	
	static GLint faces[6][4] =
	{
		{0, 1, 2, 3},
		{1, 5, 6, 2},
		{5, 4, 7, 6},
		{4, 0, 3, 7},
		{2, 6, 7, 3},
		{0, 4, 5, 1}
	};
	
	// normals
	static GLdouble n[6][3] =	
	{
		{-1.0, 0.0, 0.0},
		{0.0, 0.0, 1.0},
		{1.0, 0.0, 0.0},
		{0.0, 0.0, -1.0},
		{0.0, 1.0, 0.0},
		{0.0, -1.0, 0.0}
	};
	
	GLdouble v[8][3];
	GLint i;
	
	v[0][0] = v[1][0] = v[2][0] = v[3][0] = xMin;
	v[4][0] = v[5][0] = v[6][0] = v[7][0] = xMax;
	v[0][1] = v[1][1] = v[4][1] = v[5][1] = yMin;
	v[2][1] = v[3][1] = v[6][1] = v[7][1] = yMax;
	v[0][2] = v[3][2] = v[4][2] = v[7][2] = zMin;
	v[1][2] = v[2][2] = v[5][2] = v[6][2] = zMax;
	
	glPushMatrix();
		glBegin( GL_QUADS );
			for (i = 0; i < 6; ++i)
			{
				glNormal3dv(&n[i][0]);
				glTexCoord2d(0.0, 0.0);
				glVertex3dv(&v[faces[i][0]][0]);
				glTexCoord2d(1.0, 0.0);
				glVertex3dv(&v[faces[i][1]][0]);
				glTexCoord2d(1.0, 1.0);
				glVertex3dv(&v[faces[i][2]][0]);
				glTexCoord2d(0.0, 1.0);
				glVertex3dv(&v[faces[i][3]][0]);
			}
		glEnd();
	glPopMatrix();
}

void COpenGLPlotter::DrawLines(Streams& streams)
{
	long lCount = (long)(streams.size());
	lCount = lCount / 6;
	glBegin(GL_LINES);
	for (long lIndex = 0; lIndex < lCount; lIndex ++)
	{
		glVertex3f((GLfloat)(streams[lIndex*6 + 0]),
			(GLfloat)(streams[lIndex*6 + 1]),
			(GLfloat)(streams[lIndex*6 + 2]));

		glVertex3f((GLfloat)(streams[lIndex*6 + 3]),
			(GLfloat)(streams[lIndex*6 + 4]),
			(GLfloat)(streams[lIndex*6 + 5]));
	}
	glEnd();
}

void COpenGLPlotter::SetColor(float red, float green, float blue)
{
	glColor3f(red, green, blue);
}

void COpenGLPlotter::DrawLineArrow(Streams& streams)
{
	DrawLineArrow(streams[0], streams[1], streams[2],
		streams[3], streams[4], streams[5],
		streams[6], streams[7]);
}

void COpenGLPlotter::DrawLineArrow(double x, double y, double z,
								   double dx, double dy, double dz,
								   double length, double height)
{
	CVec startPt = CVec(x, y, z);
	CVec dir = CVec(dx, dy, dz);
	CVec endPt = startPt + dir * length;
	CVec Dir = endPt - startPt;
	Dir.Identify();

	glBegin(GL_LINES);
	glVertex3f((GLfloat)(startPt[0]), (GLfloat)(startPt[1]), (GLfloat)(startPt[2]));
	glVertex3f((GLfloat)(endPt[0]), (GLfloat)(endPt[1]), (GLfloat)(endPt[2]));
	glEnd();

	CVec headStartPt = endPt - dir * height;
	CVec endToHeadStart = headStartPt - endPt;
	CVec Axis(1, 0, 0);
	endToHeadStart.Identify();
	if (Axis == endToHeadStart)
	{
		Axis = CVec(0, 1, 0);
	}
	CVec rot = Axis ^ endToHeadStart;
	endToHeadStart.RotateBy(rot, SK_PI/3.0);
	CVec end2 = endPt + endToHeadStart * height;
	glBegin(GL_LINES);
	glVertex3f((GLfloat)(endPt[0]), (GLfloat)(endPt[1]), (GLfloat)(endPt[2]));
	glVertex3f((GLfloat)(end2[0]), (GLfloat)(end2[1]), (GLfloat)(end2[2]));
	glEnd();

	endToHeadStart.RotateBy(Dir, 2*SK_PI / 3.0);
	CVec end3 = endPt + endToHeadStart * height;
	glBegin(GL_LINES);
	glVertex3f((GLfloat)(endPt[0]), (GLfloat)(endPt[1]), (GLfloat)(endPt[2]));
	glVertex3f((GLfloat)(end3[0]), (GLfloat)(end3[1]), (GLfloat)(end3[2]));
	glEnd();

	endToHeadStart.RotateBy(Dir, 2*SK_PI / 3.0);
	CVec end4 = endPt + endToHeadStart * height;
	glBegin(GL_LINES);
	glVertex3f((GLfloat)(endPt[0]), (GLfloat)(endPt[1]), (GLfloat)(endPt[2]));
	glVertex3f((GLfloat)(end4[0]), (GLfloat)(end4[1]), (GLfloat)(end4[2]));
	glEnd();
}